package browsermanager
import com.hp.hpl.jena.rdf.model.*
import com.hp.hpl.jena.query.*
import com.hp.hpl.jena.graph.*
import com.hp.hpl.jena.ontology.*

class FileUpdaterService {
    static transactional = true
	def model= null
	def nTripleReader= null
	def wsdl= [:]
	
	def update() {
		model= ModelFactory.createDefaultModel()
		nTripleReader= model.getReader("N-TRIPLE")
		loadModel()
		extractMessages()
		extractOperations()
		extractBindings()
		extractServices()
		extractCois()
		extractHasBindings()
		extractHasOperations()
		extractProvisions()
		extractInterop()
		model.close()
	}
	
	def deleteAll() {
		nextgen.Coi.list().each { x -> x.delete() }
		nextgen.WebService.list().each { x -> x.delete() }
		nextgen.Binding.list().each { x -> x.delete() }
		nextgen.Operation.list().each { x -> x.delete() }
		nextgen.Message.list().each { x -> x.delete() }
		nextgen.Interoperability.list().each { x -> x.delete() }
	}
	
	def download(address) {
	    def rdf= address.toURL().openStream()
		nTripleReader.read(model, rdf, "")
	}
	
	def loadModel() {
		download("http://localhost:8084/Catalog/nextgen/rdf/nt")
		download("http://localhost:8081/Provision/nextgen/rdf/nt")
		download("http://localhost:8082/Interoperability/nextgen/rdf/nt")
		
		def catalog= "http://localhost:8084/Catalog/nextgen".toURL().openStream()
		def webservices= new XmlSlurper().parse(catalog)
		webservices.webService.each { service ->
			wsdl["${service.uri}"]= "${service.url}"
			def wsOnt= "http://localhost:8084/Catalog/nextgen/rdf/nt?url=${service.url}".toURL().openStream()
			nTripleReader.read(model, wsOnt, "http://www.jpdo.gov/nextgen/${service.name.toString().replaceAll(' ', '')}")
		}
	}
	
	// query the rdf model and add coi info to domain model
	def extractCois() {
		def query= """
		PREFIX jpdo: <http://www.jpdo.gov/nextgen#>
		SELECT ?service ?coi
		WHERE { ?service jpdo:inCoi ?coi }
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def serviceUrl= fact[0].toString()
			def coiName= fact[1].toString().tokenize('^^')[0]
			def service= nextgen.WebService.findByUrl(serviceUrl)
			if (nextgen.Coi.findByName(coiName)) {
				def coi= nextgen.Coi.findByName(coiName)
				coi.addToHasServices(service)
				coi.save()
			}
			else {
				def coi= new nextgen.Coi()
				coi.name= coiName
				coi.addToHasServices(service)
				coi.save()
			}
		}
	}
	
	// query the rdf model and add web service info to domain model
	def extractServices() {
		def query= """
		PREFIX wsdl: <http://www.w3.org/ns/wsdl-rdf#>
		SELECT ?url ?name
		WHERE {
			?url a wsdl:Service .
			?url wsdl:localName ?name .
		}
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def url= fact[0].toString()
			def name= fact[1].toString()
			
			def service= new nextgen.WebService()
			service.wsdl= wsdl[url]
			service.url= url
			service.name= name
			service.save()
		}
	}
	
	def extractHasBindings() {
		def query= """
		PREFIX wsdl: <http://www.w3.org/ns/wsdl-rdf#>
		SELECT ?service ?binding
		WHERE {
			?service wsdl:usesBinding ?binding
		}
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def binding= nextgen.Binding.findByUrl(fact[1].toString())
			def service= nextgen.WebService.findByUrl(fact[0].toString())
			service.addToHasBindings(binding)
			service.save()
			
			binding.setInService(service)
			binding.save()
		}
	}
	
	def extractBindings() {
		def query= """
		PREFIX wsdl: <http://www.w3.org/ns/wsdl-rdf#>
		SELECT ?url ?name
		WHERE {
			?url a wsdl:Binding .
			?url wsdl:localName ?name .
		}
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def url= fact[0].toString()
			def name= fact[1].toString()
			
			def binding= new nextgen.Binding()
			binding.url= url
			binding.name= name
			binding.save()
		}
	}
	
	def extractHasOperations() {
		def query= """
		PREFIX wsdl: <http://www.w3.org/ns/wsdl-rdf#>
		SELECT ?binding ?operation
		WHERE {
			?binding wsdl:bindingOperation ?operation
		}
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def operation= nextgen.Operation.findByUrl(fact[1].toString())
			def binding= nextgen.Binding.findByUrl(fact[0].toString())
			binding.addToHasOperations(operation)
			binding.save()
			
			def service= binding.inService
			operation.inService= service
			operation.save()
		} 
	}
	
	def extractOperations() {
		def query= """
		PREFIX wsdl: <http://www.w3.org/ns/wsdl-rdf#>
		SELECT ?url ?name ?input ?output
		WHERE {
			?url a wsdl:InterfaceOperation .
			?url wsdl:localName ?name .
			?url wsdl:interfaceMessageReference ?input .
			?input a wsdl:InputMessage .
			?url wsdl:interfaceMessageReference ?output .
			?output a wsdl:OutputMessage .
		}
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def url= fact[0].toString()
			def name= fact[1].toString()
			def input= nextgen.Message.findByUrl(fact[2].toString())
			def output= nextgen.Message.findByUrl(fact[3].toString())
			
			def operation= new nextgen.Operation()
			operation.url= url
			operation.name= name
			operation.input= input
			operation.output= output
			operation.save()
		}
	}
	
	def extractMessages() {
		def query= """
		PREFIX wsdl: <http://www.w3.org/ns/wsdl-rdf#>
		SELECT ?url ?name
		WHERE {
			{ ?url a wsdl:InputMessage }
			UNION
			{ ?url a wsdl:OutputMessage } .
			?url wsdl:localName ?name
		}
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def url= fact[0].toString()
			def name= fact[1].toString()
			def message= new nextgen.Message()
			message.url= url
			message.name= name
			message.save()
		}
	}
	
	// query the rdf model and add interoperability info to the domain model
	def extractInterop() {
		def query= """
		PREFIX jpdo: <http://www.jpdo.gov/nextgen#>
		SELECT ?from ?to
		WHERE {	?from jpdo:canConnectTo ?to }
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def from= nextgen.Operation.findByUrl(fact[0].toString())
			def to= nextgen.Operation.findByUrl(fact[1].toString())
			def interop= new nextgen.Interoperability()
			interop.from= from
			interop.to= to
			interop.save()
				
			def source= from.inService
			def destination= to.inService
			source.addToCanConnectTo(interop)
			source.addToToServices(destination)
			destination.addToCanReceiveFrom(interop)
			destination.addToFromServices(source)
			
			source.save()
			destination.save()
			
		}
	}
	
	def extractProvisions() {
		def query= """
		PREFIX jpdo: <http://www.jpdo.gov/nextgen#>
		SELECT ?x ?a ?b ?c
		WHERE {
		    	  { ?x jpdo:briefDescription ?a } 
			UNION { ?x  jpdo:technicalDescription ?b } 
			UNION { ?x jpdo:payload ?c }
		}
		"""
		def results= runQuery(query, model)
		results.each { fact ->
			def url= fact[0].toString()
			def brief= fact[1].toString()
			def technical= fact[2].toString()
			def payload= fact[3].toString()
			def resource= nextgen.Resource.findByUrl(url)
			if (brief != "null") { resource.brief= brief}
			if (technical != "null") { resource.technical= technical }
			if (payload != "null" && nextgen.Message.findByUrl(url)) { resource.payload= payload }
			resource.save()	
		}
		
	}
	
	def runQuery(String query, model) {
		def results= [] as Set
		def qPlan= QueryFactory.create(query)
		def execution= QueryExecutionFactory.create(qPlan, model)
		try {
			def resultSet= execution.execSelect()
			def variables= resultSet.getResultVars()
			for ( ; resultSet.hasNext() ; ) {
				def solution= resultSet.next()
				def result= []
				variables.each { var ->
					result << solution.get(var)
				}
				results << result
			}
			
		}
		finally {
			execution.close()
			return results
		}
	}
}
